grammar AnaYACC;

options {
    backtrack=true;
}

@header {
    package pl.equipo13.p7;
}

@lexer::header {
    package pl.equipo13.p7;
}

@rulecath { 

}

/* ANALISIS SINTACTICO*/
entrada: declaraciones? SEPARADOR reglas+ (SEPARADOR programas)? EOF;

/* DECLARACIONES */
declaraciones: codigo? start union ytokens* ytype* yleft*;

start: YSTART IDENT;
union: YUNION ALLAVE variables+ CLLAVE;
ytokens: YTOKEN MENOR IDENT MAYOR IDENT+;
ytype: YTYPE MENOR IDENT MAYOR IDENT+;
yleft: YLEFT (OPERADORSUMRES | OPERADORMULDIV | IDENT)+;
codigo: ABLOCKC (libreriasC | struct | variables | define)* CBLOCKC;
libreriasC: ALMOHADILLA INCLUDE MENOR IDENT PUNTO IDENT MAYOR; //REPASAR LO DE .h y .c
struct: TYPEDEF STRUCT IDENT ALLAVE variables+ CLLAVE IDENT PUNTOCOMA;
variables: (CHAR | INT | SHORT | LONG | DOUBLE | IDENT) IDENT (APARENTESIS CPARENTESIS | array)? (',' IDENT (APARENTESIS CPARENTESIS | array)?)* PUNTOCOMA;
array: ACORCHETE NUMERO? CCORCHETE;

/* REGLAS */
reglas: IDENT DOSPUNTOS (BARRAV? (IDENT | LITERAL | operadores | YPREC) codigor?)+ PUNTOCOMA; //ESTUDIAR CASO PRIMERO DE LA ENTRADA
codigor: ALLAVE (llamadar PUNTOCOMA | IDENTREGLA | asignacionr | yerror | condicional)* CLLAVE; // SE PUEDE OPTIMIZAR QUITANDO DUPLICADOS CON C
yerror: (YYERROK | YYERROR) PUNTOCOMA;
llamadar: IDENT APARENTESIS argumentosr CPARENTESIS;//PUNTOCOMA para ponerlo dentro de un if lo pongo fuera
argumentosr: (IDENTREGLA | CADENA | IDENT)? (COMA (IDENTREGLA |CADENA | IDENT))*;
arrayr: ACORCHETE IDENTREGLA CCORCHETE;
operadores: (OPERADORSUMRES | OPERADORMULDIV);
operadorcomp: MAYOR | MENOR | OPIGUAL | OPMAYORIGUAL | OPMENORIGUAL | OPAND | OPOR;
asignacionr: (IDENT arrayr IGUAL IDENTREGLA PUNTOCOMA) 
           | (IDENTREGLA IGUAL IDENT arrayr PUNTOCOMA)
           | (IDENTREGLA (IGUAL IDENTREGLA? (MAS | MENOS | ASTERISCO | DIVISION)? IDENTREGLA)+ PUNTOCOMA)
           | (IDENTREGLA IGUAL llamadar PUNTOCOMA);


/* PROGRAMAS */
programas: define* (funcion | EXTERN tipo_dato ASTERISCO? IDENT PUNTOCOMA)+;
define: ALMOHADILLA DEFINE IDENT (NUMERO | tipo_dato);
funcion: tipo_dato? IDENT APARENTESIS (argumentos1 | argumentos2) CPARENTESIS declaracion* ALLAVE instruccion* CLLAVE; //REVISAR al poner tipo_dato? una llamada es similar
buclew: WHILE APARENTESIS exp CPARENTESIS ALLAVE instruccion* CLLAVE;
buclef: FOR APARENTESIS (declaracion | PUNTOCOMA) exp PUNTOCOMA argf CPARENTESIS ALLAVE instruccion* CLLAVE;
argf: (exp | IDENT IGUAL llamada)? (COMA (exp | IDENT IGUAL llamada))*;
instruccion: registro |asignacion | condicional | declaracion | buclew | buclef 
           | llamada PUNTOCOMA | yerror | retorno | continuar | romper; 
registro: REGISTER IDENT PUNTOCOMA;
cond_arit: variable operadorcomp variable IFARIT variable DOSPUNTOS variable; 
declaracion: tipo_dato puntero arrayc? ((IGUAL) exp)? (COMA puntero arrayc? ((IGUAL) exp)?)* PUNTOCOMA;
puntero: ASTERISCO? IDENT;
arrayc: ACORCHETE exp CCORCHETE;
asignacion: puntero (PUNTO (IDENT))? IGUAL (exp | cond_arit) PUNTOCOMA;
llamada: IDENT APARENTESIS argumentos1 CPARENTESIS;
argumentos1: (exp | CADENA)? (COMA (exp | CADENA))*;
argumentos2: (tipo_dato ASTERISCO* IDENT)? (COMA tipo_dato ASTERISCO* IDENT array)*;
condicional: IF APARENTESIS exp CPARENTESIS bloque if_else?;
bloque: ALLAVE instruccion* CLLAVE | instruccion;
if_else: ELSE bloque; //Las llaves del else, las pondran los bloques
retorno: RETURN APARENTESIS (IDENT | LITERAL | llamada | NUMERO) CPARENTESIS PUNTOCOMA; 
continuar: CONTINUE PUNTOCOMA;
romper: BREAK PUNTOCOMA;
exp: (NEGADO | MENOS)? exp_sr (operadorcomp exp_sr)*;
exp_sr: exp_mult ((MAS | MENOS) exp_mult)*;
exp_mult: exp_base ((ASTERISCO | DIVISION) exp_base)*;
exp_base: OPINC? variable OPINC? | APARENTESIS (exp | exp_asg) CPARENTESIS; //AÑADIDO exp_asg para asignacion
exp_asg: variable IGUAL llamada;
variable: IDENT (PUNTO IDENT)? | NUMERO | IDENTREGLA | llamadar | LITERAL;
tipo_dato: VOID | INT | CHAR | FLOAT | IDENT | DOUBLE | FILE; //AÑADIDO como tipo de dato IDENT por los datos creados en el apartado declaraciones

/* ANALISISLEXICO*/
// TOKENS C
FILE: 'FILE';
DEFINE: 'define';
INCLUDE: 'include';
AUTO: 'auto';
BREAK: 'break';
CASE: 'case';
CHAR: 'char';
CONST: 'const';
CONTINUE: 'continue';
DEFAULT: 'default';
DO: 'do';
DOUBLE: 'double';
ELSE: 'else';
ENUM: 'enum';
EXTERN: 'extern';
FLOAT: 'float';
FOR: 'for';
GOTO: 'goto';
IF: 'if';
INT: 'int';
LONG: 'long';
REGISTER: 'register';
RETURN: 'return';
SHORT: 'short';
SIGNED: 'signed';
SIZEOF: 'sizeof';
STATIC: 'static';
STRUCT: 'struct';
SWITCH: 'switch';
TYPEDEF: 'typedef';
UNION: 'union';
UNSIGNED: 'unsigned';
VOID: 'void';
VOLATILE: 'volatile';
WHILE: 'while';
// TOKENS C - END

// TOKENS YACC
YTOKEN: '%token';
YUNION: '%union';
YLEFT: '%left';
YRIGTH: '%rigth';
YNONASOCC: '%nonasocc';
YPREC: '%prec';
YTYPE: '%type';
YSTART: '%start';
YYERROK: 'yyerrok';
YYERROR: 'YYERROR';
// TOKENS YACC - END

fragment LETRA: 'a'..'z' | 'A'..'Z';
fragment DIGITO: '0'..'9';
fragment PORCENTAJE: '%';
ASTERISCO: '*';
fragment BARRA: '/';
BARRAV: '|';
ALMOHADILLA: '#';
fragment GUIONBAJO: '_';
ALLAVE: '{';
CLLAVE: '}';
APARENTESIS: '(';
CPARENTESIS: ')';
ACORCHETE: '[';
CCORCHETE: ']';
COMILLAS: '"';
fragment COMSIMPLE: '\'';
fragment ASPERSAN: '&';
fragment DOLAR: '$';
NEGADO: '!';
IFARIT: '?';
MENOR: '<';
MAYOR: '>';
IGUAL: '=';
MAS: '+';
MENOS: '-';
DIVISION: '/';
OPINC: '++';
OPIGUAL: IGUAL IGUAL;
OPMAYORIGUAL: MAYOR IGUAL;
OPMENORIGUAL: MENOR IGUAL;
OPAND: ASPERSAN ASPERSAN;
OPOR: BARRAV BARRAV;
PUNTOCOMA: ';';
COMA: ',';
PUNTO: '.';
DOSPUNTOS: ':';
fragment COMENTARIOBB: BARRA BARRA;
fragment NUEVA_LINEA: '\n' | '\r\n';
BLANCO: (' '|'\t'|NUEVA_LINEA) {$channel=HIDDEN;};

SEPARADOR: PORCENTAJE PORCENTAJE;
ABLOCKC: PORCENTAJE ALLAVE;
CBLOCKC: PORCENTAJE CLLAVE;

// Comentarios
COMENTARIO: ('/*' (options {greedy=false;}:.)* '*/' 
            | COMENTARIOBB (options {greedy=false;}:.)* NUEVA_LINEA) {$channel=HIDDEN;};

CADENA: COMILLAS (options { greedy=false; }:.)* COMILLAS;
NUMERO: ((DIGITO)+ '.') => (DIGITO)+ '.' (DIGITO)* | (DIGITO)+;
OPERADORSUMRES: COMSIMPLE (MAS | MENOS) COMSIMPLE;
OPERADORMULDIV: COMSIMPLE (ASTERISCO | DIVISION) COMSIMPLE;
IDENT: (LETRA | GUIONBAJO) (LETRA | GUIONBAJO | DIGITO)*;
IDENTREGLA: DOLAR (DOLAR |DIGITO) (PUNTO IDENT)?;
LITERAL: COMSIMPLE ('\\n' | '\\r' | '\\0' | .) COMSIMPLE;